package com.jms.framework.beans.scan;

import com.jms.framework.beans.annotation.Component;
import com.jms.framework.beans.annotation.ComponentScanPaths;
import com.jms.framework.beans.annotation.Configuration;
import com.jms.framework.beans.creator.BeanDefinitionCreator;
import com.jms.framework.beans.creator.SingletonBeanFactoryCreator;
import com.jms.framework.config.AutoAssemblyConfigurationInitializer;
import com.jms.framework.config.JmsConfigItem;
import com.jms.framework.context.ApplicationContext;
import com.jms.framework.listener.Order;
import com.jms.tools.util.AnnotationUtils;
import com.jms.tools.util.PackageUtils;

import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * 组件扫描器，用于扫描指定路径下的类，并根据注解和接口实现进行分类处理。
 * 主要功能包括：扫描基础组件、配置类、自定义Bean创建器等，并进行相应的初始化处理。
 */
public class ComponentScanner {

    public static final String DEFAULT_COMPONENT_SCAN_PATH = "com.jms.framework";
    private List<String> baseComponentScanPaths;
    private List<String> otherConfigurationScanPaths;

    private Set<String> autoAssemblyConfigurationClassNames;
    private List<String> autoAssemblyConfigurationScanPaths;
    private List<String> allComponentScanPaths;
    private Set<String> componentScanClassNames;
    private List<Class<?>> componentScanClasses;
    private List<BeanDefinitionCreator> beanDefinitionCreators;
    private List<SingletonBeanFactoryCreator> singletonBeanFactoryCreators;

    /**
     * 构造函数，初始化各个扫描路径集合和类集合
     */
    public ComponentScanner() {
        baseComponentScanPaths = new ArrayList<>();
        otherConfigurationScanPaths = new ArrayList<>();
        autoAssemblyConfigurationScanPaths = new ArrayList<>();
        allComponentScanPaths = new ArrayList<>();
        componentScanClasses = new ArrayList<>();
        beanDefinitionCreators = new ArrayList<>();
        singletonBeanFactoryCreators = new ArrayList<>();
        componentScanClassNames = new HashSet<>();
        autoAssemblyConfigurationClassNames = new HashSet<>();
    }

    /**
     * 获取已扫描到的组件类列表
     *
     * @return 已扫描到的组件类列表
     */
    public List<Class<?>> getComponentScanClasses() {
        return componentScanClasses;
    }

    /**
     * 获取已扫描到的Bean定义创建器列表
     *
     * @return Bean定义创建器列表
     */
    public List<BeanDefinitionCreator> getBeanDefinitionCreators() {
        return beanDefinitionCreators;
    }

    /**
     * 获取已扫描到的单例Bean工厂创建器列表
     *
     * @return 单例Bean工厂创建器列表
     */
    public List<SingletonBeanFactoryCreator> getSingletonBeanFactoryCreators() {
        return singletonBeanFactoryCreators;
    }

    /**
     * 扫描组件并进行相关配置处理
     *
     * @param applicationContext 应用上下文对象，用于获取JMS配置和启动类信息
     * @throws ClassNotFoundException 当类加载过程中找不到指定类时抛出
     * @throws IOException 当IO操作出现异常时抛出
     * @throws InstantiationException 当实例化对象失败时抛出
     * @throws IllegalAccessException 当访问权限不足时抛出
     */
    public void scan(ApplicationContext applicationContext) throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException {
        // 进行基础扫描
        List<String> baseComponentScanPaths = Arrays.asList(applicationContext.getJmsConfig().getAttribute(JmsConfigItem.COMPONENT_SCAN_BASE_PATHS.getValue()).split(","));
        addScanPathAll(this.baseComponentScanPaths, baseComponentScanPaths);
        addScanPath(this.baseComponentScanPaths, DEFAULT_COMPONENT_SCAN_PATH);
        unitScan(this.baseComponentScanPaths);

        // 进行自动装配扫描
        getAutoAssemblyConfigurationScanPaths();
        unitScan(autoAssemblyConfigurationScanPaths);

        // 进行其他扫描
        unitScan(otherConfigurationScanPaths);

        // 对Creator进行排序
        beanDefinitionCreators.sort(Order::compareTo);
        singletonBeanFactoryCreators.sort(Order::compareTo);
    }


    /**
     * 执行单次扫描操作，根据类路径扫描类并进行分类处理
     *
     * @param scanPaths 需要扫描的路径列表
     * @throws IOException 当IO操作出现异常时抛出
     * @throws ClassNotFoundException 当类加载过程中找不到指定类时抛出
     * @throws InstantiationException 当实例化对象失败时抛出
     * @throws IllegalAccessException 当访问权限不足时抛出
     */
    private void unitScan(List<String> scanPaths) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        if (scanPaths == null || scanPaths.size() == 0) {
            return;
        }
        String[] componentScanPaths = scanPaths.toArray(new String[0]);
        List<String> classNames = PackageUtils.getClassNameByPackageName(true, componentScanPaths);
        for (String className : classNames) {
            if (!componentScanClassNames.add(className)) {
                continue;
            }
            componentScanClassNames.add(className);
            Class<?> clazz = Class.forName(className);
            componentScanClasses.add(clazz);
            if (clazz.isAnnotation() || clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
                continue;
            }
            if (AnnotationUtils.hasAnnotation(clazz, Component.class)) {
                // 如果是自定义的BeanDefinitionCreator
                if (BeanDefinitionCreator.class.isAssignableFrom(clazz)) {
                    beanDefinitionCreators.add((BeanDefinitionCreator) clazz.newInstance());
                    continue;
                }
                // 如果是自定义的SingletonBeanFactoryCreator
                if (SingletonBeanFactoryCreator.class.isAssignableFrom(clazz)) {
                    singletonBeanFactoryCreators.add((SingletonBeanFactoryCreator) clazz.newInstance());
                    continue;
                }
                // 如果是配置类
                if (AnnotationUtils.hasAnnotation(clazz, Configuration.class)) {
                    ComponentScanPaths annotation = (ComponentScanPaths) AnnotationUtils.getAnnotationByTargetAnnotation(clazz, ComponentScanPaths.class);
                    if (annotation != null) {
                        addScanPathAll(otherConfigurationScanPaths, Arrays.asList(annotation.value()));
                    }
                }
            }
        }
    }

    /**
     * 将路径列表中的所有路径添加到扫描路径集合中
     * @param scanPaths 扫描路径集合，用于存储需要扫描的路径
     * @param paths 要添加的路径列表
     */
    private void addScanPathAll(List<String> scanPaths, List<String> paths) {
        // 遍历所有路径并逐个添加到扫描路径中
        for (String path : paths) {
            addScanPath(scanPaths, path);
        }
    }

    /**
     * 添加单个扫描路径到扫描路径集合中，避免重复添加
     * @param scanPaths 扫描路径集合，用于存储需要扫描的路径
     * @param path 要添加的路径
     */
    private void addScanPath(List<String> scanPaths, String path) {
        // 如果路径为空或空字符串，则直接返回
        if (path == null || path.isEmpty()) {
            return;
        }

        // 检查路径是否已存在于当前扫描路径集合中，如果存在则不添加
        for (String scanPath : scanPaths) {
            if (path.startsWith(scanPath)) {
                return;
            }
        }

        // 检查路径是否已存在于全局组件扫描路径集合中，如果存在则不添加
        for (String scanPath : allComponentScanPaths) {
            if (path.startsWith(scanPath)) {
                return;
            }
        }

        // 将路径添加到当前扫描路径集合和全局组件扫描路径集合中
        scanPaths.add(path);
        allComponentScanPaths.add(path);
    }


    /**
     * 获取自动装配配置的扫描路径
     * 该方法会加载所有自动装配配置类，并解析其中的ComponentScanPaths注解来获取扫描路径
     *
     * @throws ClassNotFoundException 当无法找到指定的类时抛出此异常
     */
    private void getAutoAssemblyConfigurationScanPaths() throws ClassNotFoundException {
        // 获取自动装配配置类
        getAutoAssemblyConfigurations();
        for (String className : autoAssemblyConfigurationClassNames) {
            componentScanClassNames.add(className);
            Class<?> clazz = Class.forName(className);
            componentScanClasses.add(clazz);
            // 跳过注解、接口和抽象类
            if (clazz.isAnnotation() || clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
                continue;
            }
            // 检查类是否有Configuration注解，并获取其中的ComponentScanPaths注解
            if (AnnotationUtils.hasAnnotation(clazz, Configuration.class)) {
                ComponentScanPaths annotation = (ComponentScanPaths) AnnotationUtils.getAnnotationByTargetAnnotation(clazz, ComponentScanPaths.class);
                if (annotation != null) {
                    addScanPathAll(autoAssemblyConfigurationScanPaths, Arrays.asList(annotation.value()));
                }
            }
        }
    }

    /**
     * 获取自动装配配置类
     * 通过ServiceLoader机制加载所有AutoAssemblyConfigurationInitializer实现类
     */
    private void getAutoAssemblyConfigurations() {
        ServiceLoader<AutoAssemblyConfigurationInitializer> autoAssemblyLoader = ServiceLoader.load(AutoAssemblyConfigurationInitializer.class);
        for (AutoAssemblyConfigurationInitializer initializer : autoAssemblyLoader) {
            autoAssemblyConfigurationClassNames.add(initializer.getClass().getName());
        }
    }



    /**
     * 清理所有集合资源，释放内存
     */
    public void destroy() {
        baseComponentScanPaths.clear();
        otherConfigurationScanPaths.clear();
        autoAssemblyConfigurationScanPaths.clear();
        allComponentScanPaths.clear();
        componentScanClasses.clear();
        beanDefinitionCreators.clear();
        singletonBeanFactoryCreators.clear();
        componentScanClassNames.clear();
        autoAssemblyConfigurationClassNames.clear();

        baseComponentScanPaths = null;
        otherConfigurationScanPaths = null;
        autoAssemblyConfigurationScanPaths = null;
        allComponentScanPaths = null;
        componentScanClasses = null;
        beanDefinitionCreators = null;
        singletonBeanFactoryCreators = null;
        componentScanClassNames = null;
        autoAssemblyConfigurationClassNames = null;
    }
}

